package com.feishi.core.util.common;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;


/**
 * Created by caixq on 3/13 013.
 */
public class EncryptUtil {
	static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
			'9', 'A', 'B', 'C', 'D', 'E', 'F' };

	public static String encrypt(String str, String type) {
		try {
			MessageDigest messageDigest = MessageDigest.getInstance(type);
			messageDigest.update(str.getBytes());
			byte[] digest = messageDigest.digest();
			return getFormattedText(digest).toUpperCase();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static String getFormattedText(byte[] bytes) {
		final StringBuilder buf = new StringBuilder(bytes.length * 2);
		for (byte aByte : bytes) {
			buf.append(hexDigits[(aByte >> 4) & 0x0f]);
			buf.append(hexDigits[aByte & 0x0f]);
		}
		return buf.toString();
	}
	public static byte[] getByteFromFormattedText(String formattedText) {
		char[] chars=formattedText.toUpperCase().toCharArray();
		byte[] bs=new byte[chars.length/2];
		for (int i = 0; i*2 < chars.length; i++) {
			bs[i]=(byte) (getByte(chars[2*i])<<4|getByte(chars[2*i+1]));
		}
		return bs;
	}

	private static byte getByte(char c) {
		return (byte) (c>57?(c-55):(c-48));
	}
	public final static String ENCRYPT_TYPE_MD5 = "MD5";
	public final static String ENCRYPT_TYPE_SHA512 = "SHA-512";
	public final static String ENCRYPT_TYPE_SHA256 = "SHA-256";
	public final static String ENCRYPT_TYPE_SHA1 = "SHA-1";

	public static String MD5(String string) {
		return encrypt(string, ENCRYPT_TYPE_MD5);
	}

	public static String SHA512(String string) {
		return encrypt(string, ENCRYPT_TYPE_SHA512);
	}

	public static String SHA256(String string) {
		return encrypt(string, ENCRYPT_TYPE_SHA256);
	}

	public static String SHA1(String string) {
		return encrypt(string, ENCRYPT_TYPE_SHA1);
	}
	public static String encodeBase64(String str) {
		return encodeBase64(str.getBytes(StringUtil.UTF_8));
	}
	public static String encodeBase64(byte[] bytes) {

		return Base64.getEncoder().encodeToString(bytes);
	}

	public static byte[] decodeBase64(String str) {
		return Base64.getDecoder().decode(str);
	}
	public static String encodeDES(byte[] content, String key) {
		return symmetricEncode("DES", null, "DES", content,key);
	}
	public static byte[] decodeDES(String  content, String key) throws Exception {
		return symmetricDecode("DES", null, "DES", content,key);
	}
	public static String encodeDES(byte[] encryptString,String key,String iv){
		return symmetricEncode("DES/CBC/PKCS5Padding", null, "DES",encryptString,key,iv);
	}
	public static byte[] decodeDES(String encryptString, String key, String iv){
		return symmetricDecode("DES/CBC/PKCS5Padding", null, "DES",encryptString,key,iv);
	}
	public static String encodeAES(byte[] content, String key) {
		return symmetricEncode("AES", "AES", "AES", content, key);
	}
	public static byte[] decodeAES(String content, String key) {
		return symmetricDecode("AES", "AES", "AES", content, key);
	}
	public static String encodeAES128(byte[] content, String key) {
		return symmetricEncode("AES/ECB/NoPadding", null, "AES", content, key);
	}
	public static byte[] decodeAES128(String content, String key) {
		return symmetricDecode("AES/ECB/NoPadding", null, "AES", content, key);
	}
    public static String encodeAES(byte[] content, String key,String iv) {
    	return symmetricEncode("AES/CBC/PKCS5Padding", "AES", "AES", content,key,iv);
    }
    public static byte[] decodeAES(String content, String key, String iv) {
    	return symmetricDecode("AES/CBC/PKCS5Padding", "AES", "AES", content, key,iv);
    }
    public static String encodeAES_ISO(byte[] content, String key,String iv) {
    	return symmetricEncode("AES/CBC/ISO10126Padding", null, "AES", content,key,iv);
    }
    public static byte[] decodeAES_ISO(String content, String key, String iv) {
    	return symmetricDecode("AES/CBC/ISO10126Padding", null, "AES", content, key,iv);
    }
    public static String symmetricEncode(String type,String keyGenerator,String keyFormat,byte[] byteContent, String key){
    	try {
            byte[] enCodeFormat = getKeyBytes(key,keyGenerator);
    		SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, keyFormat);
    		Cipher cipher = Cipher.getInstance(type);
    		cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    		byte[] byteRresult = cipher.doFinal(byteContent);
            return getFormattedText(byteRresult);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	return null;
    }
    public static byte[] symmetricDecode(String type,String keyGenerator,String keyFormat,String content, String key){
    	if (content.length() < 1)
    		return null;
    	byte[] byteRresult =getByteFromFormattedText(content);
    	try {
            byte[] enCodeFormat = getKeyBytes(key,keyGenerator);
    		SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, keyFormat);
    		Cipher cipher = Cipher.getInstance(type);
    		cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    		byte[] result = cipher.doFinal(byteRresult);
    		return result;
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	return null;
    }
    public static String symmetricEncode(String type,String keyGenerator,String keyFormat,byte[] byteContent, String key,String iv){
        try {

            byte[] enCodeFormat = getKeyBytes(key,keyGenerator);
            IvParameterSpec ivpara=new IvParameterSpec(iv.getBytes());
            SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, keyFormat);
            Cipher cipher = Cipher.getInstance(type);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec,ivpara);
            byte[] byteRresult = cipher.doFinal(byteContent);
            return getFormattedText(byteRresult);
        } catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
    public static byte[] symmetricDecode(String type,String keyGenerator,String keyFormat,String content, String key,String iv){
        if (content.length() < 1)
            return null;
        byte[] byteRresult =getByteFromFormattedText(content);
        try {
        	IvParameterSpec ivpara=new IvParameterSpec(iv.getBytes());
            byte[] enCodeFormat = getKeyBytes(key,keyGenerator);
            SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, keyFormat);
            Cipher cipher = Cipher.getInstance(type);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec,ivpara);
            byte[] result = cipher.doFinal(byteRresult);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

	
	private static byte[] getKeyBytes(String key, String keyGenerator) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		// TODO Auto-generated method stub
        if(keyGenerator==null){
        	return key.getBytes("ASCII");
        }else{
        	KeyGenerator kgen = KeyGenerator.getInstance(keyGenerator);
        	kgen.init(128, new SecureRandom(key.getBytes()));
        	SecretKey secretKey = kgen.generateKey();
        	return secretKey.getEncoded();
        }
	}
	public static String byte2str(byte[] encrtypeByte){
		StringBuilder sb=new StringBuilder();
		for(byte b : encrtypeByte){
			int ii=b&0xff;
			String hex=Integer.toHexString(ii);
			sb.append(hex.length()==1?"0"+hex:hex);
		}
		return sb.toString();
	}
	public static void main(String[] args) throws UnsupportedEncodingException {
//		ByteArrayOutputStream out=new ByteArrayOutputStream();
//
//		for (int i = 0; i < 15; i++) {
//			out.write((int) (Math.random()*1000));
//		}
//		String data=EncryptUtil.getFormattedText(out.toByteArray());
//		String key="1234567890123456";
//		System.out.println(encodeAES(data.getBytes(),key));
//		System.out.println(encodeAES_ISO(data.getBytes(),key,key));
//		System.out.println(encodeAES(data.getBytes(),key,"1234567890123456"));
		String msg="6B228FCE52A051654E0A6D778054901A59275BB65EADFF0C62114EEC5F889AD8517462104E3A60A8901A4FE1670D52A1768468656881FF0C8BA960A8548C7F8E597D751F6D3B65E096508054901A3002003200345C0F65F6670D52A170ED7EBF00310030003000310030";
		System.out.println(new String(getByteFromFormattedText(msg),"GBK"));
		System.out.println(msg.length());
		System.out.println(decodeUnicode(insertUnicode(msg)));
	}

	/*
	 * unicode编码转中文
	 */
	public static String insertUnicode(final String data) {
		StringBuffer sb=new StringBuffer();
		for (int i = 0; i <data.length() ; i+=4) {
			sb.append("\\u"+data.substring(i,i+4));
		}
		return sb.toString();
	}
	/*
	 * 中文转unicode编码
	 */
	public static String gbEncoding(final String gbString) {
		char[] utfBytes = gbString.toCharArray();
		String unicodeBytes = "";
		for (int i = 0; i < utfBytes.length; i++) {
			String hexB = Integer.toHexString(utfBytes[i]);
			if (hexB.length() <= 2) {
				hexB = "00" + hexB;
			}
			unicodeBytes = unicodeBytes + "\\u" + hexB;
		}
		return unicodeBytes;
	}
	/*
	 * unicode编码转中文
	 */
	public static String decodeUnicode(final String dataStr) {
		int start = 0;
		int end = 0;
		final StringBuffer buffer = new StringBuffer();
		while (start > -1) {
			end = dataStr.indexOf("\\u", start + 2);
			String charStr = "";
			if (end == -1) {
				charStr = dataStr.substring(start + 2, dataStr.length());
			} else {
				charStr = dataStr.substring(start + 2, end);
			}
			char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
			buffer.append(Character.valueOf(letter).toString());
			start = end;
		}
		return buffer.toString();
	}
}
